/**
 * <p>列表数据的列设置</p>
 * @class
 * @param {String} name  列ID
 * @param {String} title 列标题
 * @param {String} desc  列描述
 * @param {Widget} type  控件类型
 * @param {boolean} pk    是否主键
 * @param {boolean} readOnly  是否只读
 * @param {Object} conf  配置项
 */
zxt.data.ColumnMeta = function(name, title, desc, type, pk, readOnly, conf){
	this._name = name || "";
	this._title = title || "";
	this._desc = desc || "";
	this._type = type || "";	
	this._primaryKey =  pk || false;
	this._readOnly = readOnly || false;
	this._regex = null;
	this._regexDesc = null;
	this._conf = conf;
};

/**
 * <p>该函数有两个功能: 当不传参数时, 返回当前的列名, 传入参数时, 设置列名</p>
 * @function
 * @param v {String} 列名
 * @return {String} 不传参数时, 返回当前的列名
 */
zxt.data.ColumnMeta.prototype.name = function(v){
  if (v === undefined) {	return this._name;	}
  this._name = v;
};

/**
 * <p>该函数有两个功能: 当不传参数时, 返回当前的列标题, 传入参数时, 设置列标题</p>
 * @function
 * @param v {String} 列标题
 * @return {String} 不传参数时, 返回当前的列标题
 */
zxt.data.ColumnMeta.prototype.title = function(v){
  if (v === undefined) {	return this._title;	}
  this._title = v;
};

/**
 * <p>该函数有两个功能: 当不传参数时, 返回当前的列描述, 传入参数时, 设置列列描述</p>
 * @function
 * @param v {String} 列描述
 * @return {String} 不传参数时, 返回当前的列描述
 */
zxt.data.ColumnMeta.prototype.desc = function(v){
  if (v === undefined) {	return this._desc;	}
  this._desc = v;
};

/**
 * <p>该函数有两个功能: 当不传参数时, 返回当前的列控件类型, 传入参数时, 设置列类型</p>
 * @function
 * @param v {Widegt} 列控件类型
 * @return {String} 不传参数时, 返回当前的列控件类型
 */
zxt.data.ColumnMeta.prototype.type = function(v){
  if (v === undefined) {	return this._type;	}
  this._type = v;
};

/**
 * <p>该函数有两个功能: 当不传参数时, 返回当前的列正则表达式, 传入参数时, 设置列正则表达式</p>
 * @function
 * @param v {Regex} 正则表达式
 * @return {Regex} 不传参数时, 返回当前的列正则表达式
 */
zxt.data.ColumnMeta.prototype.regex = function(v){
  if (v === undefined) {	return this._regex;	}
  this._regex = v;
};

/**
 * <p>该函数有两个功能: 当不传参数时, 返回当前的列正则表达式描述, 传入参数时, 设置列正则表达式的描述</p>
 * @function
 * @param v {String} 描述
 * @return {String} 不传参数时, 返回当前的列正则表达式描述
 */
zxt.data.ColumnMeta.prototype.regexDesc = function(v){
  if (v === undefined) {	return this._regexDesc;	}
  this._regexDesc = v;
};

/**
 * <p>该函数有两个功能: 当不传参数时, 返回当前的列正则表达式描述, 传入参数时, 设置列正则表达式的描述</p>
 * @function
 * @param v {String} 描述
 * @return {String} 不传参数时, 返回当前的列正则表达式描述
 */
zxt.data.ColumnMeta.prototype.readOnly = function(v){
  if (v === undefined) {	return this._readOnly;	}
  this._readOnly = v;
};

/**
 * <p>该函数有两个功能: 当不传参数时, 返回当前的列是否是主键, 传入参数时, 设置列是否是主键</p>
 * @function
 * @param v {boolean} 是否主键
 * @return {boolean} 不传参数时, 返回当前的列是否是主键，true:是主键
 */
zxt.data.ColumnMeta.prototype.primaryKey = function(v){
  if (v === undefined) {	return this._primaryKey;	}
  this._primaryKey = v;
};

/**
 * <p>该函数有两个功能: 当不传参数时, 返回当前的列配置参数, 传入参数时, 设置列配置参数</p>
 * @function
 * @param v {Object} 配置参数
 * @return {boolean} 不传参数时, 返回当前列的配置参数
 */
zxt.data.ColumnMeta.prototype.conf = function(v){
  if (v === undefined) {	return this._conf;	}
  this._conf = v;
};

/**
 * <p>表数据模型事件列表</p>
 */
zxt.data.TableModelEvents = {
  LOD   :   0,	  //加载数据
  NEW   :   1,    //add
  DEL   :   2,    //delete
  UPD   :   3,    //update
  COT   :   4,    //commit
  PRM   :   5	  //传参数
};

/**
 * <p>数据模型的抽象基类</p>
 * @class
 */
zxt.data.TableModel = function() {  
  this.listerners = [];
  this.choosed = false;//标识是否被选中
};

/**
 * <p>记录数</p>
 * @function
 * @abstract
 * @return
 */
zxt.data.TableModel.prototype.count = function(){
};

/**
 * <p>获得指定起始点的数据集</p>
 * @function
 * @abstract
 * @param offset 指定起始点
 * @param limit 指定记录条数
 * @return
 */
zxt.data.TableModel.prototype.get = function(offset, limit){
};

/**
 * <p>加载指定起始位置的数据</p>
 * @function
 * @abstract
 * @param {int} pos 指定起始位置
 * @return
 */
zxt.data.TableModel.prototype.load = function(pos){
};

/**
 * <p>保存数据</p>
 * @function
 * @abstract
 * @param {Object} v 属性对象 
 * @param {Object} i 属性名对应的值
 * @return
 */
zxt.data.TableModel.prototype.save = function(v, i){
};

/**
 * <p>新增数据</p>
 * @param {Object} t 属性对象
 * @return
 */
zxt.data.TableModel.prototype.add = function(t){
};

/**
 * <p>删除数据</p>
 * @param {Object} t 属性对象
 * @return
 */
zxt.data.TableModel.prototype.remove = function(t){
};

/**
 * <p>设置参数值,并刷新表格数据</p>
 * @param {Object} t 属性对象
 * @return
 */
zxt.data.TableModel.prototype.setParam = function(p){
};

/**
 * <p>添加监听事件的控件处理对象</p>
 * @param  {Object} l 控件处理对象
 * @return
 */
zxt.data.TableModel.prototype.addListener = function(l){
  this.listerners.push(l);
};

/**
 * <p>获取列对像集合</p>
 * @return
 */
zxt.data.TableModel.prototype.getColumns = function(){	
};

/**
 * <p>通知器</p>
 * @param {zxt.data.TableModelEvents} e 表数据模型事件
 * @param {zxt.ui.GridBase} param 控件对象
 * @return
 */
zxt.data.TableModel.prototype.notify = function(e, param){
  for( var i=0; i<this.listerners.length; i++ ){
	  var l = this.listerners[i];
	  l.accept(e, param);
  }
};

/**
 * <p>判断行数据间是否完全一致</p>
 * @param {zxt.ui.GridRow} v1 行对象
 * @param {zxt.ui.GirdRow} v2 行对象
 * @return {boolean} true:一致
 */
zxt.data.TableModel.prototype.same = function(v1, v2){	
	var cols = this.getColumns();	
	for( var i=0; i<cols.length; i++ ){
		var col = cols[i];
		var name = col.name();
		if ( v1[name] != v2[name] ) return false;	
	};	
	return true;
};	

/**
 * <p>判断行数据的主键值是否相等</p>
 * @param {zxt.ui.GridRow} v1 行对象
 * @param {zxt.ui.GirdRow} v2 行对象
 * @return {boolean} true:相等
 */
zxt.data.TableModel.prototype.equals = function(v1, v2){	
	var cols = this.getColumns();	
	for( var i=0; i<cols.length; i++ ){
		var col = cols[i];		
		if ( col.primaryKey() ){		
			var name = col.name();
			if ( v1[name] != v2[name] ) return false;	
		}
	};	
	return true;
};

/**
 * <p>TunnelTableModel继承自TableModel</p>
 * @class
 * @param {Function} service sevice方法
 */
zxt.data.TunnelTableModel = function(service) { 
	zxt.data.TableModel.call(this);
	this._mode = 0;
	if ( ! ( zxt.util.isUndefined(service) )){
		this._mode = 1;
		this._service = service;
	} 	
	
	this._async = false;
	this._param = null;
	this._sheetMetas = null;//包含列表头设置的属性对象
	
	this._count = -1;
	this._eof = false;
	this._query = "query";
	this._insert = "insert";
	this._update = "update";
	this._remove = "remove";	
	
	this._callback = null;
	this._clear = false;
	
};

zxt.defineClazz(zxt.data.TunnelTableModel, zxt.data.TableModel);

/**
 * <p>绑定列表方法</p>
 * @param {String} query
 * @param {String} insert
 * @param {String} update
 * @param {String} remove
 * @return
 */
zxt.data.TunnelTableModel.prototype.method = function(query, insert, update, remove){
	this._query = query;
	this._insert = insert;
	this._update = update;
	this._remove = remove;
};	

/**
 * <p>异步设置</p>
 * @param {boolean} v 异步设置 true:异步
 * @return 如果没有传递参数，则返回当前异步设置
 */
zxt.data.TunnelTableModel.prototype.async = function(v){
	if (v === undefined) { return this._async;	};
	this._async = v;
};

/**
 * <p>设置回调方法</p>
 * @param {Object} v 回调方法
 * @return 如果没有传递参数，则返回当前回调方法设置
 */
zxt.data.TunnelTableModel.prototype.callback = function(v){
	if (v === undefined) { return this._callback;	};
	this._callback = v;
};	

/**
 * <p>记录条数</p>
 * @return {int} 记录条数
 */
zxt.data.TunnelTableModel.prototype.count = function(){	
	return this._count;
};

/**
 * <p>数据是否加载完成</p>
 * @return {boolean} 完成标志
 */
zxt.data.TunnelTableModel.prototype.eof = function(){	
	return this._eof;
};

/**
 * <p>获得列设置集合</p>
 * @return {zxt.data.ColumnMeta[]} 列设置集合
 */
zxt.data.TunnelTableModel.prototype.getColumns = function(){	

	var columns = new Array();
	if(this._sheetMetas&&this._sheetMetas.getColumns){
		var sheetColumns = this._sheetMetas.getColumns();//列表表头设置集合		
		for( var key in sheetColumns )
		{
			var _column = sheetColumns[key];				
			var _columnMeta = new zxt.data.ColumnMeta(_column.name, _column.descName, _column.descName, _column.displayType, _column.primaryKey, _column.readonly);							
			columns.push(_columnMeta);	
		}
	}
	return columns;
};

/**
 * <p>get方法,用来加载数据</p>
 * @param {int}  offset 加载数据起点
 * @param {limit} limit 加载记录条数
 * @return {Array}  数据集
 */
zxt.data.TunnelTableModel.prototype.get = function(offset, limit){
	var host = this;	
	var rows = new Array();
	
	if ( this._count == 0 )
		return rows;
	
	var callback = { 
		onSuccess: function(ei){
			var block = ei.getSheet("result");
			if ( zxt.util.isValue(block) ){
				host._sheetMetas = block.sheetMeta();
				host._count = block.get("__total");			
				rows = block.getMappedRows();//获取数据集
			}
			
			if ( zxt.util.isValue(host._callback) ){ host._callback.onSuccess(ei, rows); };
		},
		onFailure: function(xmlR, status, e){			 
			if ( zxt.util.isValue(host._callback) ){ 
				host._callback.onFailure(xmlR, status, e); 
			} else {
				alert("Error in TunnelTableModel Ajax Get!"); 
			};	
		}
	}; 

	var dw = new zxt.data.DataWrapper();
	var sheet = new zxt.data.DataSheet("result");
	sheet.set("__offset", offset);	
	if ( zxt.util.isValue(limit) ){
		sheet.set("__limit", limit);
	}

	for( var key in this._param ){
		sheet.set(key,this._param[key]);
	};	
	
	dw.addSheet(sheet);
	
	if ( this._mode == 0 ){
		EiCommunicator.commit(this._query, dw, callback, this._async);//AJAX提交
	} else {
		EiCommunicator.send(this._service, this._query, dw, callback, this._async);	//Form提交
	}	
	
	return rows;
};

/**
 * <p>更新列表数据</p>
 * @param {Object} arr 数据对象
 * @param {Object} args 属性对象
 * @return
 */
zxt.data.TunnelTableModel.prototype.save = function(arr, args){	
	var host = this;	
	
	var callback = { 
		onSuccess: function(ei){
			if ( zxt.util.isValue(host._callback) ){ host._callback.onSuccess(ei); };
		},
		onFailure: function(xmlR, status, e){
			if ( zxt.util.isValue(host._callback) ){ 
				host._callback.onFailure(xmlR, status, e); 
			} else {
				alert("Error in TunnelTableModel Ajax Save!"); 
			};		
		}
	}; 

	
	var sheet = new zxt.data.DataSheet("result");
	sheet.sheetMeta(this._sheetMetas);
	
	for( var i=0; i<arr.length; i++ ){
		var _row = sheet.getMappedArray(arr[i]);
		sheet.addRow(_row);	
	};
	
	if ( zxt.util.isValue(args) ){
		for( var key in args ){
			sheet.set(key, args[key]);
		};	
	};
	
	var dw = new zxt.data.DataWrapper();
	dw.addSheet(sheet);
	
	if ( this._mode == 0 ){
		EiCommunicator.commit(this._update, dw, callback, this._async);
	} else {
		EiCommunicator.send(this._service, this._update, dw, callback, this._async);
	}
	
	this.notify( zxt.data.TableModelEvents.UPD, {} );
	
};

/**
 * <p>新增列表数据</p>
 * @param {Object} arr 数据对象
 * @param {Object} args 属性对象
 * @return
 */
zxt.data.TunnelTableModel.prototype.add = function(arr, args){
	var host = this;	
	
	var callback = { 
		onSuccess: function(ei){
			if ( zxt.util.isValue(host._callback) ){ host._callback.onSuccess(ei); };
		},
		onFailure: function(xmlR, status, e){
			if ( zxt.util.isValue(host._callback) ){ 
				host._callback.onFailure(xmlR, status, e); 
			} else {
				alert("Error in TunnelTableModel Ajax Add!"); 
			};	
		}
	}; 

	
	var sheet = new zxt.data.DataSheet("result");
	sheet.sheetMeta(this._sheetMetas);
	
	for( var i=0; i<arr.length; i++ ){
		var _row = sheet.getMappedArray(arr[i]);
		sheet.addRow(_row);
	}
	
	if ( zxt.util.isValue(args) ){
		for( var key in args ){
			sheet.set(key, args[key]);
		};	
	};
	
	var dw = new zxt.data.DataWrapper();
	dw.addSheet(sheet);
	
	if ( this._mode == 0 ){
		EiCommunicator.commit(this._insert, dw, callback, this._async);
	} else {
		EiCommunicator.send(this._service, this._insert, dw, callback, this._async);
	}
	
	this.notify( zxt.data.TableModelEvents.NEW, t );
};

/**
 * <p>删除列表数据</p>
 * @param {Object} arr 数据对象
 * @param {Object} args 属性对象
 * @return
 */
zxt.data.TunnelTableModel.prototype.remove = function(arr, args){
	var host = this;	
	
	var callback = { 
		onSuccess: function(ei){
			if ( zxt.util.isValue(host._callback) ){ host._callback.onSuccess(ei); };			
		},
		onFailure: function(xmlR, status, e){
			if ( zxt.util.isValue(host._callback) ){ 
				host._callback.onFailure(xmlR, status, e); 
			} else {
				alert("Error in TunnelTableModel Ajax Remove!"); 
			};	
		}
	}; 

	
	var sheet = new zxt.data.DataSheet("result");
	sheet.sheetMeta(this._sheetMetas);
	
	for( var i=0; i<arr.length; i++ ){
		var _row = sheet.getMappedArray(arr[i]);
		sheet.addRow(_row);
	}
	
	if ( zxt.util.isValue(args) ){
		for( var key in args ){
			sheet.set(key, args[key]);
		};	
	};
	
	var dw = new zxt.data.DataWrapper();
	dw.addSheet(sheet);
	
	if ( this._mode == 0 ){
		EiCommunicator.commit(this._remove, dw, callback, this._async);
	} else {
		EiCommunicator.send(this._service, this._remove, dw, callback, this._async);
	}
	
	this.notify( zxt.data.TableModelEvents.DEL, {} );
};

/**
 * <p>该函数有两个功能: 当不传参数时, 返回当前的参数配置, 传入参数时, 设置参数配置</p>
 * @function
 * @param v {Object} 参数
 * @return {Object} 不传参数时, 返回当前的参数配置
 */
zxt.data.TunnelTableModel.prototype.parameter = function(v){
	if (v === undefined) {	return this._param;	}
	this._param = v;
};	

/**
 * <p>设置参数，并触发Grid的对象的PRM事件处理方法，加载表格数据</p>
 * @function
 * @param {Object} p 参数对象
 * @return 
 */
zxt.data.TunnelTableModel.prototype.setParam = function(p){
	this._count = -1;
	this._eof = false;
	this._param = p;//保存传入的参数,在get方法用到
	this.notify( zxt.data.TableModelEvents.PRM, p );
};

/**
 * <p>清空表格数据</p>
 * @function
 * @return
 */
zxt.data.TunnelTableModel.prototype.clear = function(){
	this._count = 0;
	this.notify( zxt.data.TableModelEvents.PRM, null );
};	

/**
 * <p>该函数有两个功能: 当不传参数时, 返回当前的列表头配置, 传入参数时, 设置列表头</p>
 * @function
 * @param v {Object} 参数
 * @return {Object} 不传参数时, 返回当前的列表头配置
 */
zxt.data.TunnelTableModel.prototype.sheetMetas = function(v){
	if(v===undefined){return this._sheetMetas;}
	this._sheetMetas = v;
};


/**
 * <p>CVSTable,添加了缓存功能</p>
 * @param service
 */
zxt.data.CVSTableModel = function(service) { 
	zxt.data.TunnelTableModel.call(this, service);
	
	this._cached = [];
	this._cacheStart = 0;	
};

zxt.defineClazz(zxt.data.CVSTableModel, zxt.data.TunnelTableModel);

/**
 * <p>当不传参数时, 返回当前的缓存数据</p>
 * @function
 * @param v {Object} 参数
 * @return {Array} 不传参数时, 返回当前的缓存数据
 */
zxt.data.CVSTableModel.prototype.cached = function(v){
	if ( v == undefined ){return this._cached};
};	

/**
 *<p>填充数据</p>
 * @private
 * @param offset
 * @param limit
 * @return
 */
zxt.data.CVSTableModel.prototype._fill = function(offset, limit){
	var host = this;	
	var _cacheEnd = this._cacheStart + this._cached.length;
	
	var _end = offset + limit; 	
	// if ( this._count >=0 ){
		// _end = this._count;
	// }	
	 
	if ( offset >= this._cacheStart && _end <= _cacheEnd ){//判断是否需要从后台取数据，如果包含在缓存数据中，则不需要
		return;
	};
	
	if(this.eof()){//已加载所有数据
		return;
	}
	
	var rows = [];
	var eof = false;
	var count = -1;
	if ( _end > _cacheEnd ){	
		var callback = { 
			onSuccess: function(ei){			
				var block = ei.getSheet("result");
				if ( zxt.util.isValue(block) ){
					host._sheetMetas = block.sheetMeta();
					var _eof = block.get("__eof");
					eof = _eof == "1"?true:false;
					rows = block.getMappedRows();//返回的记录集
					count = block.get("__total");
				}
				if ( zxt.util.isValue(host._callback) ){ host._callback.onSuccess(ei); };
			},
			onFailure: function(xmlR, status, e){
				if ( zxt.util.isValue(host._callback) ){ 
					host._callback.onFailure(xmlR, status, e); 
				} else {
					alert("Error in CVSTableModel Ajax Get!"); 
				};
			}
		}; 
	
		var dw = new zxt.data.DataWrapper();
		var sheet = new zxt.data.DataSheet("result");
		
		var fetch_size = _end - _cacheEnd;//要从后台取的记录数
		sheet.set("__offset", _cacheEnd);
		sheet.set("__limit", fetch_size);
		
		for( var key in this._param ){
			sheet.set(key,this._param[key]);
		};
		
		if ( this._cached.length > 0 ){	//保存最后一条记录，用于翻页查询	
			var last = this._cached[this._cached.length-1];
			for( var key in last ){
				sheet.set(key, last[key]);
			};
		};
		
		dw.addSheet(sheet);
		
		if ( this._mode == 0 ){
			EiCommunicator.commit(this._query, dw, callback, this._async);
		} else {
			EiCommunicator.send(this._service, this._query, dw, callback, this._async);	
		};			
	};
	
	if ( rows.length > 0 ){
		this._cached = this._cached.concat(rows);	//增加缓存数据
		if ( !eof )//需要继续取数据填充
			this._fill(offset, limit);
	};
	if(count!=-1&&count)
		this._count = count;
	
	if ( eof ){
		this._eof = true;
		this._count = this._cached.length;
		this.notify( zxt.data.TableModelEvents.COT, {} );
	}
};	

/**
 * <p>取数据</p>
 * @param {int} offset 起始计数
 * @param {int} limit 查询一次记录数目
 * @return {Array} 数据记录集
 */
zxt.data.CVSTableModel.prototype.get = function(offset, limit){
	if( this._count == 0 ){
		return [];
	};	
		
	this._fill(offset, limit);
	
	var _cacheEnd = this._cacheStart + this._cached.length;
	var _end = offset + limit; 
	
	var t_start = offset - this._cacheStart;
	var t_end = t_start + limit;
	
	return this._cached.slice(t_start, t_end);
};

/**
 * <p>设置参数</p>
 * @param {Object} p 参数
 * @return
 */
zxt.data.CVSTableModel.prototype.setParam = function(p){
	this._param = p;//保存参数
	this._cached = [];
	this._count = -1;
	this._eof = false;
	this.notify( zxt.data.TableModelEvents.PRM, p );//触发Listener
};

/**
 * <p>ListTableModel，继承自zxt.data.TableModel</p>
 * @class
 * @param li
 * @param cols
 */
zxt.data.ListTableModel = function(li, cols) {
	this.base = zxt.data.TableModel;
	this.base();
	
	this._list = li;		
	this._filtered = null;
	this._param = null;
	this.columns = cols;
	
	this.setParam(this._param);
};

zxt.defineClazz(zxt.data.ListTableModel, zxt.data.TableModel);

/**
 * <p>记录数</p>
 * @return
 */
zxt.data.ListTableModel.prototype.count = function(){	
	return this._filtered.length;
};

/**
 * <p>加载指定起始位置的数据</p>
 * @function 
 * @param {int} pos 指定起始位置
 * @return {Array} 指定起始位置的数据
 */
zxt.data.ListTableModel.prototype.load = function(pos){
  if ( pos <0 || pos >= this._filtered.length) { return null; };
  var idx = this._filtered[pos];
  return this._list[idx];
};

/**
 * <p>取数据</p>
 * @param {int} offset 起始计数
 * @param {int} limit 查询一次记录数目
 * @return {Array} 数据记录集
 */
zxt.data.ListTableModel.prototype.get = function(offset, limit){
	if ( offset < 0 ){ offset = 0; };
	var ret = [];
	var upLimit = this._filtered.length;
	if ( upLimit > offset+limit ){ upLimit = offset+limit; };
	for( var i=offset; i<upLimit; i++ ){
		var idx = this._filtered[i];  	
		ret.push( this._list[idx] );
	};
	return ret;
};

/**
 * <p>更新列表数据</p>
 * @param {Object} arr 数据对象  
 * @return
 */
zxt.data.ListTableModel.prototype.save = function(arr){
	
	throw new Error("ListTableModel Save NOT supported");
	
	if ( arr.length > 1 ){
		throw new Error("ListTableModel allow one row to save!");
	}
	var t = arr[0];
  var idx = this._filtered[i];
  this._list[idx] = t;
  
  this.notify( zxt.data.TableModelEvents.UPD, {} );
};

/**
 * <p>新增列表数据</p>
 * @param {Object} arr 数据对象 
 * @return
 */
zxt.data.ListTableModel.prototype.add = function(arr){
	for(var i=0; i<arr.length; i++){
  	this._list.push(arr[i]); 
  };
  this.setParam(this._param); 
  this.notify( zxt.data.TableModelEvents.NEW, {} );
};

/**
 * <p>删除列表数据</p>
 * @param {Object} arr 数据对象
 * @return
 */
zxt.data.ListTableModel.prototype.remove = function(arr){
	for( var i=0; i<arr.length; i++ ){
		var v = arr[i];	
		var lastIdx = this._list.length - 1;			
		for( var i=lastIdx; i>=0; i-- ){
			var _item = this._list[i];
			if ( this.equals(_item, v) ){
				this._list.splice(i, 1);
			}	
		};	
	};
	
	this.notify( zxt.data.TableModelEvents.DEL, {} );	
};	

/**
 * <p>删除指定位置的列表数据</p>
 * @param {int} i 位置索引
 * @return
 */
zxt.data.ListTableModel.prototype.removeAt = function(i){	
  if ( i < 0 || i >= this._filtered.length ) { return; };
  var _idx =  this._filtered[i];  
  
  var piece1 =  this._list.slice(0, _idx);
  var piece2 = this._list.slice( _idx + 1 );
  this._list = piece1.concat(piece2);
  this.setParam(this._param); 
  this.notify( zxt.data.TableModelEvents.DEL, {} );
};

/**
 * <p>判断数据是否一致</p>
 * @private
 * @param {Object} item 数据项
 * @param {Object} param 参数项
 * @return {Boolean} true:数据一致  false:数据不一致
 */
zxt.data.ListTableModel.prototype._filter = function(item, param){
	if ( param == null )
		return true;	
	
	for(var key in param){
		var val = param[key];		
		if (zxt.util.isAvailable(val)){
				var myVal = item[key];
				if ( myVal != val ){
					return false;
				};	
		};	
	};	
		
	return true;	
};	

/**
 * <p>设置参数</p>
 * @param {Object} p 参数
 * @return
 */
zxt.data.ListTableModel.prototype.setParam = function(p){
	this._filtered = [];
	for( var i=0; i<this._list.length; i++ ){
		var _item = this._list[i];
		var _satisfy = this._filter(_item, p);
		if( _satisfy ){
			this._filtered.push(i);
		};	
	};	
	this._param = p;
	this.notify( zxt.data.TableModelEvents.PRM, p );
};

/**
 * <p>清空表格数据</p>
 * @return
 */
zxt.data.ListTableModel.prototype.clear = function(){
	this._filtered = [];
	this.notify( zxt.data.TableModelEvents.PRM,  null);
}	

/**
 * <p>获得列头属性</p>
 * @return
 */
zxt.data.ListTableModel.prototype.getColumns = function(){
	return this.columns;
};



/* Tree Model  */
zxt.data.TreeModelEvents = {
  LOD   :   1,
  DEL   :   2,
  UPD   :   3,
  COT   :   4,
  PRM   :   5	  
};

/**
 * <p>树模型的基类</p>
 * @class
 */
zxt.data.TreeModel = function() {  
  this.listerners = [];
};

/**
 * <p>获得顶层节点</p>
 * @return
 */
zxt.data.TreeModel.prototype.getTopNodes = function(){
};

/**
 * <p>获取孩子节点</p>
 * @param p
 * @return
 */
zxt.data.TreeModel.prototype.getChildren = function(p){
};

/**
 * <p>获取父亲节点</p>
 * @param p
 * @return
 */
zxt.data.TreeModel.prototype.getParent = function(p){
	alert('getParent NOT implemented');
};

/**
 * <p>设置监听器</p>
 * @param l
 * @return
 */
zxt.data.TreeModel.prototype.addListener = function(l){
  this.listerners.push(l);
};

/**
 * <p>设置告知器</p>
 * @param {Event} e 事件
 * @param {Object} param 参数
 * @return
 */
zxt.data.TreeModel.prototype.notify = function(e, param){
	for( var i=0; i<this.listerners.length; i++){
		var l = this.listerners[i];
		l.accept(e, param);
	};  
};

/**
 * <p>TunnelTreeModel,继承自TreeModel</p>
 * @class
 * @param s
 */
zxt.data.TunnelTreeModel = function(s) {
	zxt.data.TreeModel.call(this);
	this._service = s;
	this._cache = {};
	this._param = null;


	this._childrenM = "children";
	this._parentM = "parent";
};

zxt.defineClazz(zxt.data.TunnelTreeModel, zxt.data.TreeModel);

/**
 * <p>设置孩子、父亲节点</p>
 * @param children
 * @param parent
 * @return
 */
zxt.data.TunnelTreeModel.prototype.method = function(children, parent){
	this._childrenM = children;
	this._parentM = parent;
};	

/**
 * <p>设置参数</p>
 * @param {Object} p 参数
 * @return
 */
zxt.data.TunnelTreeModel.prototype.setParam = function(p){
	this._param = p;
};

/**
 * <p>获得顶层节点</p>
 * @return
 */
zxt.data.TunnelTreeModel.prototype.getTopNodes = function(){
  return this.getChildren("$");
};

/**
 * <p>获得孩子节点</p>
 * @param p
 * @return
 */
zxt.data.TunnelTreeModel.prototype.getChildren = function(p){
	var host = this;
	var cached = this._cache[p];
	if ( zxt.util.isValue( cached ) ){ return cached;  }
    
	var callback = { 
		onSuccess: function(dw){			 
			var sheets = dw.getSheets();
			for( var k in sheets ){
				var sheet = sheets[k];
				var rows = sheet.getMappedRows();
				host._cache[k] = rows;
			}
		},
		onFail: function(xmlR, status, e){ alert("ERROR"); }
	}; 
	
	var dw = new zxt.data.DataWrapper();
	var sheet = new zxt.data.DataSheet("result");
	sheet.set("__node", p+"");	
	
	for( var key in this._param ){
		sheet.set(key,this._param[key]);
	};
	
	dw.addSheet(sheet);
	EiCommunicator.send(this._service, this._childrenM, dw, callback, false);		
    
	var ret = this._cache[p];
	if ( zxt.util.isValue(ret) ){
	  delete this._cache[p];
	  return ret;
	} else {
	  return new Array();
	}
};


/**
 * <p>ListTreeModel链表树模型，继承自TreeModel</p>
 * @param {Object} li 模型数据集
 */
zxt.data.ListTreeModel = function(li) {
	zxt.data.TreeModel.call(this);
	
	this.list = li;	//保存链表树模型数据
	this.idK = "label";
	this.parentK = "parent";
};

zxt.defineClazz(zxt.data.ListTreeModel, zxt.data.TreeModel);

/**
 * <p>获取顶层节点</p>
 * @return {Object} Parent为空的顶层节点
 */
zxt.data.ListTreeModel.prototype.getTopNodes = function(){
  return this.getChildren("");
};

/**
 * <p>获取同一父节点设置的孩子节点集</p>
 * @param {String} p Parent设置
 * @return {Array} 孩子节点集
 */
zxt.data.ListTreeModel.prototype.getChildren = function(p){
  var nodes = new Array();
  for( var i in this.list ){
    var t = this.list[i];
		if ( t[this.parentK] == p ){  nodes.push(t); };
  };
  return nodes;
};

/**
 * <p>获取父节点</p>
 * @param {String} m 
 * @return
 */
zxt.data.ListTreeModel.prototype.getParent = function(m){
  var me = this._getNode(m);
  if ( me != null ){
	  var pl = me[this.parentK];
	  return this._getNode(pl);
  };
  return null;
};

/**
 * @private
 * @param lb
 * @return
 */
zxt.data.ListTreeModel.prototype._getNode = function(lb){
  for( var i in this.list ){
    var t = this.list[i];
		if ( t[this.idK] == lb ){		
			return t;
		};
  };
  return null;
};

/**
 * <p>对象树模型，继承自TreeModel</p>
 * @class
 */
zxt.data.ObjectTreeModel = function() {
	zxt.data.TreeModel.call(this);
	this.childs = {};
	this.nodes = {};
};

zxt.defineClazz(zxt.data.ObjectTreeModel, zxt.data.TreeModel);

/**
 * <p>获取顶层节点</p>
 * @return {Array} 顶层节点
 */
zxt.data.ObjectTreeModel.prototype.getTopNodes = function(){
  return this.getChildren("");
};

/**
 * <p>获取同一父节点设置的孩子节点集</p>
 * @param {String} p Parent设置
 * @return {Array} 孩子节点集
 */
zxt.data.ObjectTreeModel.prototype.getChildren = function(p){
  var cached = this.childs[p];
  if ( zxt.util.isAvailable( cached ) ){ return cached;  }
  var em = new Array();
  return em;
};

/**
 * <p>获得父节点</p>
 * @param m
 * @return
 */
zxt.data.ObjectTreeModel.prototype.getParent = function(m){
  var nd = this.nodes[m];
  if ( nd != null ){
	  var p = this.nodes[nd.parent];
	  return p;
  };
  return null;
};

/**
 * <p>添加孩子节点</p>
 * @param {Stirng} p 父节点设置
 * @param {Object} node 节点对象
 * @return
 */
zxt.data.ObjectTreeModel.prototype.addChild = function(p, node){
  var children = this.getChildren( p );
  children.push(node);
  this.childs[p] = children;
  this.nodes[node.label] = node;
};

/**
 * <p>XmlTreeModel,继承自TreeModel</p>
 * @class
 * @param {XML} s XML文件
 */
zxt.data.XmlTreeModel = function(s) {
	zxt.data.TreeModel.call(this);
  this.nodes = {};
	this.parseXML(s);
};

zxt.defineClazz(zxt.data.XmlTreeModel, zxt.data.TreeModel);

/**
 * <p>获取顶层节点</p>
 * @return {Array} 顶层节点
 */
zxt.data.XmlTreeModel.prototype.getTopNodes = function(){
  return this.getChildren("");
};

/**
 * <p>获取同一父节点设置的孩子节点集</p>
 * @param {String} p Parent设置
 * @return {Array} 孩子节点集
 */
zxt.data.XmlTreeModel.prototype.getChildren = function(p){
  var cached = this.nodes[p];
  if ( zxt.util.isAvailable( cached ) ){ return cached;  };
  var em = new Array();
  return em;
};

/**
 * <p>添加孩子节点</p>
 * @param {Stirng} p 父节点设置
 * @param {Object} node 节点对象
 * @return
 */
zxt.data.XmlTreeModel.prototype.addChild = function(p, node){
  var children = this.getChildren( p );
  children.push(node);
  this.nodes[p] = children;
};

/**
 * <p>解析XML</p>
 * @param {Object} sSrc Dom 节点
 * @return
 */
zxt.data.XmlTreeModel.prototype.parseXML = function(sSrc){
  var oXmlDoc = null;
  if (window.ActiveXObject) {
    oXmlDoc=new ActiveXObject("Microsoft.XMLDOM");
    oXmlDoc.async="true";
    oXmlDoc.loadXML(sSrc);
  } else {
    var parser=new DOMParser();
    oXmlDoc=parser.parseFromString(sSrc,"text/xml");
  };
 
  var root = oXmlDoc.documentElement;
  this._parseXMLNode( "",root );
};

/**
 * @private
 * @param p
 * @param oNode
 * @return
 */
zxt.data.XmlTreeModel.prototype._parseXMLNode = function(p, oNode){
	var cs = oNode.childNodes;
	var len = cs.length;
	for (var i = 0; i < len; i++) {
		var oNode = cs[i];
		if ( oNode.tagName == "tree" ) {      
	    var tNode = {};
	    for( var k=0; k<oNode.attributes.length; k++ ) {
		    var l = oNode.attributes[k].nodeName;
		    var v = oNode.attributes[k].nodeValue;
		    tNode[l] = v;
			};
			this.addChild(p, tNode);
			this._parseXMLNode( tNode["label"], oNode );
		};
	};
};
